
package com.jf.cloud.order.controller.supplier;


import com.jf.cloud.api.auth.constant.SysTypeEnum;
import com.jf.cloud.api.order.constant.OrderStatus;
import com.jf.cloud.api.vo.EsPageVO;
import com.jf.cloud.common.database.dto.PageDTO;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.order.constant.ReturnProcessStatusEnum;
import com.jf.cloud.common.order.dto.OrderRefundSearchDTO;
import com.jf.cloud.common.order.vo.EsOrderRefundVO;
import com.jf.cloud.common.response.ResponseEnum;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.common.rocketmq.config.RocketMqConstant;
import com.jf.cloud.common.security.AuthUserContext;
import com.jf.cloud.order.constant.RefundApplyType;
import com.jf.cloud.order.constant.RefundStsType;
import com.jf.cloud.order.constant.RefundType;
import com.jf.cloud.order.constant.SupplierHandleStatus;
import com.jf.cloud.order.dto.multishop.OrderRefundDTO;
import com.jf.cloud.order.model.Order;
import com.jf.cloud.order.model.OrderItem;
import com.jf.cloud.order.model.OrderRefundAddr;
import com.jf.cloud.order.model.OrderSettlement;
import com.jf.cloud.order.service.*;
import com.jf.cloud.order.vo.OrderRefundAddrVO;
import com.jf.cloud.order.vo.OrderRefundVO;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import ma.glasnost.orika.MapperFacade;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.api.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;
import java.util.Objects;


/**
 * @author zz
 */
@RestController("supplierOrderRefundController")
@RequestMapping("/s/order_refund")
@Tag(name = "供应商端订单退款")
public class OrderRefundController {
    private final Logger LOGGER = LoggerFactory.getLogger(OrderRefundController.class);

    @Autowired
    private OrderRefundService orderRefundService;
    @Autowired
    private OrderRefundAddrService orderRefundAddrService;
    @Autowired
    private MapperFacade mapperFacade;
    @Autowired
    private RocketMQTemplate orderRefundTemplate;
    @Autowired
    private OrderSettlementService orderSettlementService;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private OrderService orderService;

    /**
     * 查看我的退款订单列表
     */
    @GetMapping("/page")
    @Operation(summary = "我的退款订单列表" , description = "我的退款订单列表，显示数量")
    public ServerResponseEntity<EsPageVO<EsOrderRefundVO>> list(PageDTO page, @ParameterObject OrderRefundSearchDTO orderRefundPageDTO) {
        orderRefundPageDTO.setSupplierId(AuthUserContext.get().getTenantId());
        orderRefundPageDTO.setSysType(AuthUserContext.get().getSysType());
        EsPageVO<EsOrderRefundVO> pageList = orderRefundService.page(page, orderRefundPageDTO);
        return ServerResponseEntity.success(pageList);
    }

    /**
     * 通过id查询
     *
     * @param refundId id
     * @return 查询详细信息
     */
    @GetMapping("/info/{refundId}")
    public ServerResponseEntity<OrderRefundVO> getById(@ParameterObject @PathVariable("refundId") Long refundId) {
        OrderRefundVO orderRefund = orderRefundService.getDetailByRefundId(refundId);
        if (!Objects.equals(orderRefund.getSupplierId(), AuthUserContext.get().getTenantId())) {
            return ServerResponseEntity.fail(ResponseEnum.UNAUTHORIZED);
        }
        if (Objects.equals(orderRefund.getApplyType(), RefundApplyType.REFUND_AND_RETURNS.value())&& orderRefund.getHandelTime() !=null) {
            OrderRefundAddr orderRefundAddr = orderRefundAddrService.getByRefundId(refundId);
            orderRefund.setOrderRefundAddr(mapperFacade.map(orderRefundAddr, OrderRefundAddrVO.class));
        }
        return ServerResponseEntity.success(orderRefund);
    }


    /**
     * 进入这个方法，会出现两种情况：
     * 1. 仅退款，此时商家同意买家的退款申请，执行发放退款的操作
     * 2. 退货退款操作:
     *   2.1)退货退款的第一步，商家允许买家退款的申请，商家进行设置退货地址，不执行发放退款的操作
     *   2.2)退货退款的第二步，当商家收到货之后，同意买家退款，此时需要发放退款，但不会执行这个方法，执行的是下面这个方法
     *   @see OrderRefundController#returnMoney(OrderRefundDTO)
     *
     */
    @PutMapping("/return_and_refund_audit")
    public ServerResponseEntity<Void> returnAndRefundAudit(@RequestBody OrderRefundDTO orderRefundParam) {
        // 处理退款操作

        OrderRefundVO orderRefundVO = orderRefundService.getDetailByRefundId(orderRefundParam.getRefundId());
        if (!Objects.equals(ReturnProcessStatusEnum.APPLY.value(), orderRefundVO.getReturnMoneySts())) {
            // 订单退款状态已发生改变，请勿重复操作
            return ServerResponseEntity.showFailMsg("订单退款状态已发生改变，请勿重复操作");
        }
//        // 移交供应商处理，改变下状态即可
//        if (Objects.equals(orderRefundVO.getSupplierHandleStatus(), SupplierHandleStatus.TRANSFER_SUPPLIER.value())) {
//            // 订单退款状态已发生改变，请勿重复操作
//            return ServerResponseEntity.showFailMsg("订单退款状态已发生改变，请勿重复操作");
//        }
        if (!Objects.equals(orderRefundVO.getSupplierId(), AuthUserContext.get().getTenantId())) {
            return ServerResponseEntity.fail(ResponseEnum.UNAUTHORIZED);
        }
        // 拒绝退款，可以不需要分布式事务啥的，因为就单纯拒绝，发个通知给用户，做幂等处理就好了
        if (Objects.equals(orderRefundParam.getRefundSts(), RefundStsType.DISAGREE.value())) {
            orderRefundVO.setSupplierHandleStatus(SupplierHandleStatus.SUPPLIER_DISAGREE.value());
            orderRefundService.disagreeRefund(orderRefundParam, orderRefundVO);
            return ServerResponseEntity.success();
        }

        // 同意退货，可以不需要分布式事务啥的，因为就单纯拒绝，发个通知给用户，做幂等处理就好了
        if (Objects.equals(orderRefundVO.getApplyType(), RefundApplyType.REFUND_AND_RETURNS.value())) {

            orderRefundService.agreeReturns(orderRefundParam, orderRefundVO,SysTypeEnum.SUPPLIER.value());
            return ServerResponseEntity.success();
        }

        // 同意退款，上面只是同意退货，关系到钱要看下面的
        return agreeRefund(orderRefundParam,orderRefundVO);
    }

    @GetMapping("/is_last_refund")
    @Operation(summary = "是否为最后一单退款")
    public ServerResponseEntity<Boolean> isLastRefund(@ParameterObject Long refundId) {
        Long shopId = AuthUserContext.get().getTenantId();
        return ServerResponseEntity.success(orderRefundService.getIsLastRefund(refundId, shopId));
    }


    /**
     * 退货退款的第二步，当商家收到货之后，同意买家退款，此时需要发放退款
     */
    @PutMapping("/return_money")
    public ServerResponseEntity<Void> returnMoney(@Valid @RequestBody OrderRefundDTO orderRefundParam) {

        // 获取退款单信息
        OrderRefundVO orderRefundVO = orderRefundService.getDetailByRefundId(orderRefundParam.getRefundId());
        if (!Objects.equals(ReturnProcessStatusEnum.CONSIGNMENT.value(), orderRefundVO.getReturnMoneySts())) {
            throw new LuckException("订单退款状态已发生改变，请勿重复操作");
        }
        if (!Objects.equals(orderRefundVO.getSupplierId(), AuthUserContext.get().getTenantId())) {
            throw new LuckException(ResponseEnum.UNAUTHORIZED);
        }
        // 拒绝退款，可以不需要分布式事务啥的，因为就单纯拒绝，发个通知给用户，做幂等处理就好了
        if (Objects.equals(orderRefundParam.getRefundSts(), RefundStsType.DISAGREE.value())) {
            orderRefundVO.setSupplierHandleStatus(SupplierHandleStatus.SUPPLIER_DISAGREE.value());
            orderRefundService.disagreeRefund(orderRefundParam, orderRefundVO);
            return ServerResponseEntity.success();
        }

        return agreeRefund(orderRefundParam,orderRefundVO);
    }


//    @PutMapping("/refund_request")
//    public ServerResponseEntity<Void> resfundRequest(@Valid @RequestBody RefundSnDto refundSnDto) {
//        // 获取退款信息
//        OrderRefundVO orderRefundVO = orderRefundService.getDetailByRefundId(refundSnDto.getRefundId());
//        if (orderRefundVO == null) {
//            // 退款单不存在
//            throw new LuckException("退款单不存在");
//        }
//        if (orderRefundVO.getDecisionTime() == null) {
//            // 请先确定退款，才能发起退款操作
//            throw new LuckException("请先确定退款，才能发起退款操作");
//        }
//        if (orderRefundVO.getRefundTime() != null) {
//            // 已退款成功，无法再申请退款操作
//            throw new LuckException("已退款成功，无法再申请退款操作");
//        }
//        if (!Objects.equals(orderRefundVO.getShopId(), AuthUserContext.get().getTenantId())) {
//            throw new LuckException(ResponseEnum.UNAUTHORIZED);
//        }
//        if(orderRefundVO.getRefundStatus() == 2){
//            // 已退款成功，无法再申请退款操作
//            throw new LuckException("已退款成功，无法再申请退款操作");
//        }
//        if (Objects.equals(-1,orderRefundVO.getReturnMoneySts())) {
//            // 买家已取消申请
//            throw new LuckException("买家已取消申请");
//        }
//        return agreeRefund(null, orderRefundVO);
//    }

    private ServerResponseEntity<Void> agreeRefund(OrderRefundDTO orderRefundParam, OrderRefundVO orderRefundVo) {

        OrderSettlement orderSettlement = orderSettlementService.getByOrderId(orderRefundVo.getOrderId());
        if (orderSettlement == null) {
            return ServerResponseEntity.showFailMsg("没有查询到支付记录，无法申请退款");
        }

        orderRefundVo.setPayId(orderSettlement.getPayId());
        orderRefundVo.setPayType(orderSettlement.getPayType());
        orderRefundVo.setFreightAmount(0L);
        // 获取订单信息
        Order order = orderService.getOrderByOrderIdAndUserId(orderRefundVo.getOrderId(), orderRefundVo.getUserId());
        if (Objects.equals(order.getStatus(), OrderStatus.PAYED.value())) {
            // -----最后一件商品的运费计算-----------
            long freightAmount = 0L;
            // 如果存在分销订单，则计算分销总金额
            List<OrderItem> orderItemList = orderItemService.listOrderItemsByOrderId(order.getOrderId());
            // 获取所有的订单项总数
            int orderItemCount = orderItemList.size();
            //退款成功总数
            // 获取所有正在进行中的退款订单
            int refundCount = orderRefundService.countSuccessItemNum(order.getOrderId());
            //最后一单
            if (Objects.equals(refundCount, orderItemCount - 1)) {

                if (order.getFreightAmount() > 0.0 && order.getPlatformFreeFreightAmount() >= 0.0) {
                    freightAmount = order.getFreightAmount() - order.getPlatformFreeFreightAmount();
                    LOGGER.info("最后一单退款，freightAmount：{}", freightAmount);
                }
                // 单项退款，且平台减免运费---平台减免的运费要从商家钱包退还给平台，所以将运费添加到平台优惠金额中
                if (Objects.equals(orderRefundVo.getRefundType(),RefundType.SINGLE.value()) && order.getPlatformFreeFreightAmount() > 0.0) {
                    orderRefundVo.setPlatformRefundAmount(orderRefundVo.getPlatformRefundAmount() + order.getPlatformFreeFreightAmount());
                    orderRefundVo.setLastOrder(true);
                    LOGGER.info("单项退款，且平台减免运费，平台减免的运费要从商家钱包退还给平台，所以将运费添加到平台优惠金额中，platformRefundAmount：{}", orderRefundVo.getPlatformRefundAmount());
                }
            }
            // 供应商发货的订单，放进去实际的支付运费金额，用于后续的供应商金额退款
            if(Objects.equals(order.getSupplierDeliveryType(),1) && !Objects.equals(order.getSupplierId(),0L)){
                orderRefundVo.setFreightAmount(freightAmount + Math.abs(order.getFreeFreightAmount()));
                LOGGER.info("供应商发货的订单，放进去实际的支付运费金额，用于后续的供应商金额退款，freightAmount：{}", orderRefundVo.getFreightAmount());
            }
            // 只有单个退款才需要加上运费
            if(Objects.equals(orderRefundVo.getRefundType(),RefundType.SINGLE.value())) {
                // 退款金额加上运费
                orderRefundVo.setRefundAmount(orderRefundVo.getRefundAmount() + freightAmount);
                LOGGER.info("单个退款，退款金额加上运费，refundAmount：{}", orderRefundVo.getRefundAmount());
                // 平台减免运费金额的时候，添加供应商发货的订单的运费,商家退款金额需要单独减去上面退款金额中添加的运费
                // 供应商发货的订单单项退款包含的运费为商品原本的运费，不受平台和商家运费减免金额的影响（商家不能修改供应商发货订单的运费，平台减免金额是给商家的，跟供应商没有关系）
                if (Objects.nonNull(order.getPlatformFreeFreightAmount()) && order.getPlatformFreeFreightAmount() > 0.0) {
                    orderRefundVo.setSupplierFreightAmount(order.getFreightAmount());
                    LOGGER.info("平台减免运费金额的时候，添加供应商发货的订单的运费,商家退款金额需要单独减去上面退款金额中添加的运费，supplierFreightAmount：{}", orderRefundVo.getSupplierFreightAmount());
                }
            }
        }
//        orderRefundVo.setPurchaseRefundAmount(orderRefundVo.getPurchaseRefundAmount() + freightAmount);
        // 执行退款，真正意义上的退款，需要确保
        // 发送事务消息
        TransactionSendResult transactionSendResult = orderRefundTemplate.sendMessageInTransaction(RocketMqConstant.ORDER_REFUND_TOPIC, new GenericMessage<>(orderRefundVo), orderRefundParam);

        if (!Objects.equals(transactionSendResult.getLocalTransactionState(), LocalTransactionState.COMMIT_MESSAGE)) {
            LOGGER.error("退款事务消息发送失败，事务状态：{}", transactionSendResult.getLocalTransactionState());
            return ServerResponseEntity.fail(ResponseEnum.EXCEPTION);
        }
        return ServerResponseEntity.success();
    }

    private long checkLastRefund(OrderRefundVO orderRefundDto) {
        if (Objects.equals(orderRefundDto.getRefundType(), RefundType.ALL.value())) {
            return 0L;
        }
        // 获取订单信息
        Order order = orderService.getOrderByOrderIdAndUserId(orderRefundDto.getOrderId(), orderRefundDto.getUserId());
        if (!Objects.equals(order.getStatus(), OrderStatus.PAYED.value())) {
            return 0L;
        }
        //所有订单项总数

        // 如果存在分销订单，则计算分销总金额
        List<OrderItem> orderItemList = orderItemService.listOrderItemsByOrderId(order.getOrderId());
        // 获取所有的订单项总数
        int orderItemCount = orderItemList.size();
        //退款成功总数
        // 获取所有正在进行中的退款订单
        int refundCount = orderRefundService.countSuccessItemNum(order.getOrderId());
        if (Objects.equals(refundCount, orderItemCount - 1) && order.getFreightAmount() > 0.0) {
            //最后一单
            if (order.getPlatformFreeFreightAmount() == 0.0) {
                return order.getFreightAmount() - order.getPlatformFreeFreightAmount();
            }
        }
        return 0L;
    }

}
